1 为什么有操作系统
- 操作系统: 位于底层和应用软件之间
- 工作方式: 向下管理硬件 向上提供接口
1.1 操作系统进程切换:
- 出现IO操作(像time.sleep之类的)
- 固定时间(是操作系统控制的切换时间)
1.2进程的定义:
进程是一个程序在一个数据集谁给你的动态执行过程。
程序、数据集(程序过程中使用的资源)、进程控制块(切换的时候 保存状态)
进程并发的时候,如果是一个应用程序,会把资源进行传递
进程是通过进程切换,是共享的资源,保存的的时候保存的是进程的资源集
- 进程:
资源管理单位(容器)
- 线程:
最小执行单位
1.3 并行和并发的区别:
串行是线程依次执行,运行期间独享内存
并行是每个线程占用一个内核
并发是有等待

python的多线程:
由于GIL,同一时刻,同一进程只能有一个线程被运行
但是可以实现多进程的并发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import threading import time s = time.time() def listen(): print("listen") time.sleep(3) print("listen end") def blog(): print("blog") time.sleep(5) print("blog end") if __name__ == '__main__': t1 = threading.Thread(target=listen) t2 = threading.Thread(target=blog) t1.start() t2.start() print(time.time()-s) print("main ending") ''' 结果: listen blog 0.0 main ending # 这个是3个运行完毕 listen end blog end 可以证明的是实现了线程的切换 '''
|
使用join 方法,主线程会等待其余的结束后才运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import threading import time s = time.time() def listen(): print("listen") time.sleep(3) print("listen end") def blog(): print("blog") time.sleep(5) print("blog end") if __name__ == '__main__': t1 = threading.Thread(target=listen) t2 = threading.Thread(target=blog) t1.start() t2.start() t1.join() t2.join() print(time.time()-s) print("main ending") ''' 结果: listen blog listen end blog end 5.001286029815674 # 这里是线程2运行结束的时间 main ending # 最终运行主线程 '''
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 自己定义的类取执行 ```python import time import threading class MyThread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): print("the num is %s" % self.num) time.sleep(3) t1 = MyThread(56) t2 = MyThread(78) t1.start() t2.start() print("ending") ''' 结果: the num is 56 the num is 78 ending '''
|
1.4 join方法
t.join() 主线程等待对象等待完
1 2 3 4 5
| t1.start() t2.start() t1.join() t2.join()
|
如果是: 下面就是串行
1 2 3 4 5
| t1.start() t1.join() t2.start() t2.join()
|
1.5 守护线程
setDaemon
主线程结束了,子线程就结束了
线程开启之后就不能控制
有自他的子线程t1,t2的时候,t2是守护线程,主线程先等待t1,主线程结束后,守护线程关闭。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import threading from time import ctime, sleep import time def Music(name): print("Begin listening to {name}. {time}".format(name=name, time=ctime())) sleep(3) print("end listening {time}".format(time=ctime())) def Blog(title): print("Begin recording the {title}. {time}".format( title=title, time=ctime())) sleep(5) print('end recording {time}'.format(time=ctime())) threads = [] t1 = threading.Thread(target=Music, args=('music',)) t2 = threading.Thread(target=Blog, args=('blog',)) threads.append(t1) threads.append(t2) if __name__ == '__main__': t1.setDaemon(True) t2.setDaemon(True) t1.start() t2.start() print("all over %s" % ctime())
|
1.6 其他的方法
1 2 3 4 5 6 7 8 9
| Thread实例对象的方法 threading模块提供的一些方法:
|
GIL 全局解释器锁
Global Interpreter Lock
加在CPython的解释器中,只有CPyhton中受到限制
阻止多线程并行
python的多线程:
由于GIL,同一时刻,同一进程只能有一个线程被运行

使用多进程的时候就可以突破这个限制
提高效率,用协程
对于IO密集型的提高效率,不使用CPU
计算密集型,一直是在使用CPU,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import threading import time s = time.time() def counter(): sum = 0 for i in range(50000000): sum += i if __name__ == '__main__': t1 = threading.Thread(target=counter) t2 = threading.Thread(target=counter) t1.start() t2.start() t1.join() t2.join() print(time.time() - s) ''' py2.7: 串行:10.5270001888 并发:15.7999999523 py3.: 串行:6.322361707687378 并发:6.371364593505859 Python3 的GIL已经进行了优化 '''
|
总结:
对于计算密集型的任务,Python多线程没有用
对于IO密集型的任务,Python多线程有用
Python使用多核: 开多进程
弊端: 内存开销大切换复杂
解决方案:
- 使用协程,是单线程还可以自己控制切换的此时
- IO多路复用 以后大多的的应用场景
- 终极思路:C模块实现多线程